package com.yykj.user.center.server.service.impl.patient;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.yykj.common.enums.HospitalOnlineTypeEnum;
import com.yykj.common.enums.ResultEnums;
import com.yykj.common.exception.NormalException;
import com.yykj.common.service.RedisService;
import com.yykj.common.util.GsonUtil;
import com.yykj.common.util.LocalRequestUtil;
import com.yykj.common.util.LocalStringUtil;
import com.yykj.common.vo.PageData;
import com.yykj.common.vo.ResultVO;
import com.yykj.hospital.client.dto.*;
import com.yykj.hospital.client.feign.HospitalServerFeignClient;
import com.yykj.hospital.client.form.OnlineOrderForm;
import com.yykj.message.center.client.enums.OrderType;
import com.yykj.message.center.client.feign.MessageFeignClient;
import com.yykj.pay.center.client.feign.PayFeignClient;
import com.yykj.prescription.client.enums.PrescriptionType;
import com.yykj.prescription.client.feign.PrescriptionFeignClient;
import com.yykj.user.center.client.dto.ConsultationOrderInfoDTO;
import com.yykj.user.center.client.dto.ConsultationStatisticsDto;
import com.yykj.user.center.client.dto.DoctorConsultationCountDto;
import com.yykj.user.center.client.form.ConsultationOrderSearchForm;
import com.yykj.user.center.server.dto.*;
import com.yykj.user.center.server.form.*;
import com.yykj.user.center.server.model.*;
import com.yykj.user.center.server.repository.MedicalRecordRepository;
import com.yykj.user.center.server.repository.patient.*;
import com.yykj.user.center.server.service.DoctorService;
import com.yykj.user.center.server.service.patient.ConsultationInfoService;
import com.yykj.user.center.server.service.patient.PaymentService;
import com.yykj.user.center.server.utils.DateUtil;
import com.yykj.user.center.server.utils.OrderUtil;
import com.yykj.user.center.server.utils.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.math.BigDecimal;
import java.text.NumberFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author chenl
 * @version 1.0
 * @date 2021/11/6 14:22
 */
@Service
@Slf4j
public class ConsultationInfoServiceImpl implements ConsultationInfoService {
    @Autowired
    private ConsultationInfoRepository consultationInfoRepository;
    @Autowired
    private PatientCardInfoRepository patientCardInfoRepository;
    @Autowired
    private RedisService redisService;
    @Autowired
    private HospitalServerFeignClient hospitalServerFeignClient;
    @Autowired
    private FileRepository fileRepository;
    @Autowired
    private EvaluationRepository evaluationRepository;
    @Autowired
    private PaymentService paymentService;

    @Autowired
    private MedicalRecordRepository medicalRecordRepository;
    @Autowired
    private RegisterOrderRepository registerOrderRepository;
    @Autowired
    private PrescriptionFeignClient prescriptionFeignClient;

    @Autowired
    private DoctorService doctorService;
    @Autowired
    private MessageFeignClient messageFeignClient;
    @Autowired
    private PatientRepository patientRepository;

    @Autowired
    PayFeignClient payFeignClient;

    @Value("${spring.profiles.active}")
    private String prefix;

    private Specification<ConsultationInfoOrder> generateSpecification(ConsultationOrderSearchForm form) {
        return new Specification<ConsultationInfoOrder>() {
            @Override
            public Predicate toPredicate(Root<ConsultationInfoOrder> root, CriteriaQuery<?> query, CriteriaBuilder builder) {
                List<Predicate> predicateList = new ArrayList<>();
                if (StringUtils.isNotBlank(form.getId())) {
                    predicateList.add(builder.equal(root.get("id"), form.getId()));
                }
                if (StringUtils.isNotBlank(form.getPayAccountId())) {
                    predicateList.add(builder.equal(root.get("payAccountId"), form.getPayAccountId()));
                }
                if (form.getHospitalId() != null && form.getHospitalId() > 0) {
                    predicateList.add(builder.equal(root.get("hospitalId"), form.getHospitalId()));
                }
                if (form.getDeptId() != null && form.getDeptId() > 0) {
                    predicateList.add(builder.equal(root.get("deptId"), form.getDeptId()));
                }
                if (StringUtils.isNotBlank(form.getDoctorId())) {
                    predicateList.add(builder.equal(root.get("doctorId"), form.getDoctorId()));
                }
                //TODO

                if (form.getEndType() != null) {
                    predicateList.add(builder.equal(root.get("endType"), form.getEndType()));
                }
                if (form.getState() != null && form.getState().size() > 0) {
                    CriteriaBuilder.In<Integer> in = builder.in(root.get("state").as(Integer.class));
                    for (Integer state : form.getState()) {
                        in.value(state);
                    }
                    predicateList.add(in);
                }

                Predicate[] predicates = new Predicate[predicateList.size()];
                return query.where(predicateList.toArray(predicates)).getRestriction();
            }
        };
    }

    /**
     * 检查是否还在问诊中
     *
     * @param patientId
     * @param doctorId
     * @return
     */
    public boolean checkConsulting(String patientId, String doctorId) {
        Integer[] states = {0, 1, 2};
        List<ConsultationInfoOrder> consultationInfoOrderList = consultationInfoRepository.findAll(generateSpecification(ConsultationOrderSearchForm.builder()
                .endType(-1)
                .doctorId(doctorId)
                .payAccountId(patientId)
                .state(Arrays.asList(states))
                .payStatus(1)
                .build()));
        return consultationInfoOrderList.size() > 0;
    }

    private String getLock(String key) {
        boolean lockStatus = false;
        int cnt = 0;
        String lockValue = "";
        do {
            cnt++;
            lockValue = "" + (System.currentTimeMillis() + 2000);
            lockStatus = redisService.lock(key, lockValue);
            if (!lockStatus) {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

        } while (cnt < 5 && !lockStatus);
        if (!lockStatus) {
            throw new NormalException(ResultEnums.REDIS_LOCK_ERROR);
        } else {
            return lockValue;
        }
    }

    @Override
    public String create(AddConsultationOrderForm addConsultationInfoForm) {
        //是否有排班
        //订单类型：11、图文问诊 12、语音问诊 13、视频问诊
        Integer orderType = addConsultationInfoForm.getOrderType();
        HospitalOnlineTypeEnum orderTypeEnum = HospitalOnlineTypeEnum.pic;
        if (orderType != null) {
            switch (orderType) {
                case 12:
                    orderTypeEnum = HospitalOnlineTypeEnum.voice;
                    break;
                case 13:
                    orderTypeEnum = HospitalOnlineTypeEnum.video;
                    break;
            }
        }
        String doctorId = addConsultationInfoForm.getDoctorId();
        Integer appointId = addConsultationInfoForm.getAppointId();
        String lockkey = "lockappointment" + doctorId + appointId + orderType;
        String lockValue = getLock(lockkey);
        String key = "appointment" + doctorId + appointId + orderType;


        int remain = 0;
       /* String s = this.redisService.get(key);
        if (StringUtils.isEmpty(s)) {//加入缓存
            DoctorAvailableOnlineDTO doctorAvailableOnlineDTO = hospitalServerFeignClient.checkAvailableOnlineCnt(doctorId, appointId, orderTypeEnum);
            Integer remainz = doctorAvailableOnlineDTO.getRemain();
            if(remainz != null){
                remain = remainz;
            }
        }else{
            remain = StringUtil.string2int(s);
        }*/
        DoctorAvailableOnlineDTO doctorAvailableOnlineDTO = hospitalServerFeignClient.checkAvailableOnlineCnt(doctorId, appointId, orderTypeEnum);
        if (doctorAvailableOnlineDTO != null) {
            Integer remainz = doctorAvailableOnlineDTO.getRemain();
            if (remainz != null) {
                remain = remainz;
            }
        }

        if (remain == 0) {
            throw new NormalException(ResultEnums._2209);
        }
        OnlineOrderForm onlineOrderForm = new OnlineOrderForm();
        onlineOrderForm.setAppointId(appointId);
        onlineOrderForm.setCnt(1);
        onlineOrderForm.setDoctorId(doctorId);

        onlineOrderForm.setType(orderTypeEnum);
        if (this.hospitalServerFeignClient.changeAvailableOnlineCnt(onlineOrderForm) == null) {//扣库存失败
            throw new NormalException(ResultEnums._2213);
        }
        String cardId = addConsultationInfoForm.getPatientCardId();
        String strStartDateTime = addConsultationInfoForm.getStartDatetime();
        String strEndDateTime = addConsultationInfoForm.getEndDatetime();
        String date = addConsultationInfoForm.getDate();
        String strStartTime = date + " " + strStartDateTime + ":00";
        String strEndTime = date + " " + strEndDateTime + ":00";
        Integer[] states = {0, 1, 2};
//        ConsultationInfoOrder consultationInfoOrder = consultationInfoRepository.findFirstByPatientCardIdAndPayStatusAndRefundStatusAndStartDatetimeAndEndDatetimeAndStateInOrderByCreateTimeDesc(cardId, 1, -1, DateUtil.stringDateTime2DateTime(strStartTime), DateUtil.stringDateTime2DateTime(strEndTime), states);
        if (StringUtils.isBlank(addConsultationInfoForm.getPatientId())) {
            PatientCardInfo patientCardInfo = patientCardInfoRepository.findById(addConsultationInfoForm.getPatientCardId()).orElseThrow(() -> new NormalException(ResultEnums.NOT_EXIST));
            addConsultationInfoForm.setPatientId(patientCardInfo.getAccountId());
        }

        if (checkConsulting(addConsultationInfoForm.getPatientId(), addConsultationInfoForm.getDoctorId())) {
            throw new NormalException(ResultEnums.HAS_UNFINISHED_ORDER_ERROR);
        }
        String token = LocalRequestUtil.getToken();
        UserLoginInfo userLoginInfo = GsonUtil.fromJson(redisService.get(token), UserLoginInfo.class);
        String userId = userLoginInfo.getUserId();
        Integer hospitalId = addConsultationInfoForm.getHospitalId();
        ConsultationInfoOrder consultationInfo = new ConsultationInfoOrder();
        BeanUtils.copyProperties(addConsultationInfoForm, consultationInfo);
        DoctorDTO doctorDTO = hospitalServerFeignClient.info(addConsultationInfoForm.getDoctorId());
        if (doctorDTO == null || StringUtils.isEmpty(doctorDTO.getTencentAccountId())) {
            throw new NormalException(ResultEnums._2210);
        }
        consultationInfo.setDoctorTencentAccountId(doctorDTO.getTencentAccountId());
        consultationInfo.setPatientTencentAccountId(userLoginInfo.getTencentAccountId());
        String id = LocalStringUtil.getUUID();
        PatientCardInfo patientCardInfo = patientCardInfoRepository.findById(consultationInfo.getPatientCardId()).orElse(null);
        if (patientCardInfo != null) {
            BeanUtils.copyProperties(patientCardInfo, consultationInfo);
            consultationInfo.setNameFamily(patientCardInfo.getNation());
        } else {
            throw new NormalException(ResultEnums.PATIENTCARD_ERROR);
        }
        consultationInfo.setPayAccountId(userId);
        consultationInfo.setPayType(1);
        consultationInfo.setBirthday(patientCardInfo.getBirthday());
        consultationInfo.setSex(patientCardInfo.getSex());
        consultationInfo.setStartDatetime(DateUtil.stringDateTime2DateTime(strStartTime));
        consultationInfo.setEndDatetime(DateUtil.stringDateTime2DateTime(strEndTime));
        consultationInfo.setDate(DateUtil.stringDate2Date(date));
        consultationInfo.setAge(patientCardInfo.getAge());
        String orderNo = OrderUtil.getOrderNo(hospitalId, consultationInfo.getOrderType());
        consultationInfo.setOrderNo(orderNo);
        consultationInfo.setPatientName(patientCardInfo.getPatientName());
        consultationInfo.setMedicalHistory(patientCardInfo.getPresentIllnessHistory());
        //这里需要调用医生那边的接口，获取价格
        List<DoctorOnlinePriceSettingDTO> doctorOnlinePriceSettingDTOS = hospitalServerFeignClient.doctorOnlineConfigInfo(addConsultationInfoForm.getDoctorId());
        if (addConsultationInfoForm.getOrderType() == 11) {
            for (DoctorOnlinePriceSettingDTO doctorOnlinePriceSettingDTO : doctorOnlinePriceSettingDTOS) {
                if (HospitalOnlineTypeEnum.pic == doctorOnlinePriceSettingDTO.getType()) {
                    consultationInfo.setPayAmount(doctorOnlinePriceSettingDTO.getPrice());
                    break;
                }
            }
        } else if (addConsultationInfoForm.getOrderType() == 12) {
            for (DoctorOnlinePriceSettingDTO doctorOnlinePriceSettingDTO : doctorOnlinePriceSettingDTOS) {
                if (HospitalOnlineTypeEnum.voice == doctorOnlinePriceSettingDTO.getType()) {
                    consultationInfo.setPayAmount(doctorOnlinePriceSettingDTO.getPrice());
                    break;
                }
            }
        } else if (addConsultationInfoForm.getOrderType() == 13) {
            for (DoctorOnlinePriceSettingDTO doctorOnlinePriceSettingDTO : doctorOnlinePriceSettingDTOS) {
                if (HospitalOnlineTypeEnum.video == doctorOnlinePriceSettingDTO.getType()) {
                    consultationInfo.setPayAmount(doctorOnlinePriceSettingDTO.getPrice());
                    break;
                }
            }
        }
        consultationInfo.setPayTime(LocalDateTime.now());
        consultationInfo.setState(0);
        consultationInfo.setId(id);
        List<String> imgs = addConsultationInfoForm.getImgPath();
        if (imgs != null && imgs.size() > 0) {
            int i = 0;
            for (String img : imgs) {
                File file = new File();
                file.setId(LocalStringUtil.getUUID());
                file.setPath(img);
                file.setBusinessId(id);
                file.setSort(i++);
                fileRepository.save(file);
            }
        }

        consultationInfoRepository.save(consultationInfo);
        this.redisService.unlock(lockkey, lockValue);
        return orderNo;
    }

    @Override
    public List<ConsultationDoctorDTO> consultationDoctors() {
        String token = LocalRequestUtil.getToken();
        UserLoginInfo userLoginInfo = GsonUtil.fromJson(redisService.get(token), UserLoginInfo.class);
        String userId = userLoginInfo.getUserId();
        List<ConsultationInfoOrder> consultationInfoOrders = consultationInfoRepository.findAllByPayAccountIdAndStateGroupByDoctorIdOrderByCreateTimeDesc(userId, 4, 1);
        List<ConsultationDoctorDTO> consultationDoctorDTOS = new ArrayList<>();
        for (ConsultationInfoOrder consultationInfoOrder : consultationInfoOrders) {
            ConsultationDoctorDTO consultationDoctorDTO = new ConsultationDoctorDTO();
            BeanUtils.copyProperties(consultationInfoOrder, consultationDoctorDTO);
            consultationDoctorDTO.setAccountId(userId);
            DoctorDTO doctorDTO = hospitalServerFeignClient.info(consultationInfoOrder.getDoctorId());
            consultationDoctorDTO.setSkill(doctorDTO.getSkill());
            consultationDoctorDTO.setOfficer(doctorDTO.getOfficer());
            consultationDoctorDTO.setAvatar(doctorDTO.getHeadImg());
            consultationDoctorDTOS.add(consultationDoctorDTO);
        }
        return consultationDoctorDTOS;
    }

    @Override
    public Boolean updateState(UpdateConsultationOrderStateForm updateConsultationOrderStateForm) {
        ConsultationInfoOrder consultationInfoOrder = consultationInfoRepository.findById(updateConsultationOrderStateForm.getId()).orElse(null);
        if (consultationInfoOrder != null) {
            if (updateConsultationOrderStateForm.getState() == 2) {
                //不到规定时间不让接诊
                LocalDateTime startDatetime = consultationInfoOrder.getStartDatetime();
                LocalDateTime endDatetime = consultationInfoOrder.getEndDatetime();
                LocalDateTime now = LocalDateTime.now();
                /*if(now.isAfter(startDatetime) && endDatetime.isAfter(now)){
                }else{
                    throw new NormalException(ResultEnums._2212, ResultEnums._2212.getMessage() + startDatetime + "-" +endDatetime);
                }*/
                consultationInfoOrder.setReceiveTime(now);
                LocalDateTime plusTime = null;
                HospitalConfigInfo hospitalConfigInfo = hospitalServerFeignClient.hospitalConfigInfo(consultationInfoOrder.getHospitalId());
                if (hospitalConfigInfo != null) {
                    List<HospitalSettingOnlineDTO> hospitalSettingOnlineDTOS = hospitalConfigInfo.getOnlineSetting();
                    Integer orderType = consultationInfoOrder.getOrderType();
                    if (orderType == 11 || orderType == 16) {
                        for (HospitalSettingOnlineDTO hospitalSettingOnlineDTO : hospitalSettingOnlineDTOS) {
                            if (hospitalSettingOnlineDTO.getType() == HospitalOnlineTypeEnum.pic) {
                                Integer time = hospitalSettingOnlineDTO.getTime();
                                plusTime = now.plusMinutes(time);
                            }
                        }
                    } else if (orderType == 12) {
                        for (HospitalSettingOnlineDTO hospitalSettingOnlineDTO : hospitalSettingOnlineDTOS) {
                            if (hospitalSettingOnlineDTO.getType() == HospitalOnlineTypeEnum.voice) {
                                Integer time = hospitalSettingOnlineDTO.getTime();
                                plusTime = now.plusMinutes(time);
                            }
                        }
                    } else if (orderType == 13) {
                        for (HospitalSettingOnlineDTO hospitalSettingOnlineDTO : hospitalSettingOnlineDTOS) {
                            if (hospitalSettingOnlineDTO.getType() == HospitalOnlineTypeEnum.video) {
                                Integer time = hospitalSettingOnlineDTO.getTime();
                                plusTime = now.plusMinutes(time);
                            }
                        }
                    }
                    consultationInfoOrder.setServiceEndTime(plusTime);
                }
                Map dataMap = new HashMap();
                dataMap.put("type", 4);
                dataMap.put("data", "医生已接诊");
                paymentService.sendPayedMsg(consultationInfoOrder.getPatientTencentAccountId(), consultationInfoOrder.getDoctorTencentAccountId(), JSON.toJSONString(dataMap, SerializerFeature.WriteNullStringAsEmpty), 1);

                Optional<Patient> optional = this.patientRepository.findById(consultationInfoOrder.getPayAccountId());
                if(optional.isPresent()){
                    messageFeignClient.smsPatientDoctorReceive(optional.get().getMobile(),consultationInfoOrder.getDoctorName());
                }
            }
            consultationInfoOrder.setState(updateConsultationOrderStateForm.getState());
            consultationInfoRepository.save(consultationInfoOrder);
        }
        return true;
    }

    @Override
    public List<MyConsultationDTO> consultationList(String patientCardId, Integer state) {
        String token = LocalRequestUtil.getToken();
        UserLoginInfo userLoginInfo = GsonUtil.fromJson(redisService.get(token), UserLoginInfo.class);
        String userId = userLoginInfo.getUserId();
        List<ConsultationInfoOrder> consultationInfoOrders = consultationInfoRepository.findAll(new Specification<ConsultationInfoOrder>() {
            @Override
            public Predicate toPredicate(Root<ConsultationInfoOrder> root, CriteriaQuery<?> query, CriteriaBuilder builder) {
                List<Predicate> predicateList = new ArrayList<>();
                predicateList.add(builder.equal(root.get("payAccountId"), userId));
                if (StringUtils.isNotBlank(patientCardId)) {
                    predicateList.add(builder.equal(root.get("patientCardId"), patientCardId));
                }

                if (state != null) {
                    predicateList.add(builder.equal(root.get("state"), state));
                }


                Predicate[] predicates = new Predicate[predicateList.size()];
                return query.where(predicateList.toArray(predicates)).getRestriction();
            }
        }, Sort.by(Sort.Order.desc("createTime")));
        List<MyConsultationDTO> myConsultationDTOS = new ArrayList<>();
        for (ConsultationInfoOrder consultationInfoOrder : consultationInfoOrders) {
            MyConsultationDTO myConsultationDTO = new MyConsultationDTO();
            BeanUtils.copyProperties(consultationInfoOrder, myConsultationDTO);
            String businessId = myConsultationDTO.getId();
            List<File> files = fileRepository.findAllByBusinessId(businessId);
            List<String> paths = files.stream().map(File::getPath).collect(Collectors.toList());
            myConsultationDTO.setImgs(paths);
            myConsultationDTOS.add(myConsultationDTO);
        }
        return myConsultationDTOS;
    }

    @Override
    public Boolean cancel(CancelConsultationForm cancelConsultationForm) {
        ConsultationInfoOrder consultationInfoOrder = consultationInfoRepository.
                findById(cancelConsultationForm.getId()).orElseThrow(() -> new NormalException(ResultEnums.NOT_EXIST));
        //状态：0生成订单 1待接诊  2问诊中  3已完成 4已退款
        if (!consultationInfoOrder.getState().equals(2)) {
            throw new NormalException(ResultEnums.ORDER_STATUS_ERROR);
        }
        consultationInfoOrder.setAuth(0);
        consultationInfoOrder.setState(3);
        consultationInfoOrder.setEndType(0);
        consultationInfoRepository.save(consultationInfoOrder);
        //患者向医生发送服务已结束的消息
        Map<String, String> dataMap = new HashMap<>();
        dataMap.put("type", "1");
        dataMap.put("data", "本次服务已结束");
        paymentService.sendPayedMsg(consultationInfoOrder.getPatientTencentAccountId(), consultationInfoOrder.getDoctorTencentAccountId(),
                JSON.toJSONString(dataMap, SerializerFeature.WriteNullStringAsEmpty), 2);
        //医生发送消息让患者评价
        Map<String, String> msg = new HashMap<>();
        dataMap.put("type", "4");
        dataMap.put("data", "服务结束，请对本次服务进行评价");
        paymentService.sendPayedMsg(consultationInfoOrder.getDoctorTencentAccountId(), consultationInfoOrder.getPatientTencentAccountId(),
                JSON.toJSONString(dataMap, SerializerFeature.WriteNullStringAsEmpty), 2);
        Optional<Patient> optional = this.patientRepository.findById(consultationInfoOrder.getPayAccountId());
        if(optional.isPresent()){
            messageFeignClient.smsPatientConsultationFinish(optional.get().getMobile(),consultationInfoOrder.getDoctorName());
        }
        try {
            this.messageFeignClient.sendOrderFinishMessage(consultationInfoOrder.getOrderNo(), OrderType.consultation);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return true;
    }

    @Override
    public PageData<ConsultationInfoOrderDTO> list(Integer current, Integer size, String startDate, String endDate, String doctorName, String patientName, String mobile,
                                                   String orderNo, Integer orderType, Integer endType, Integer state, Integer refundStatus, Integer payStatus,
                                                   Integer hospitalId) {
        Pageable pageable = PageRequest.of(current, size, Sort.by(Sort.Order.desc("createTime")));
        Page<ConsultationInfoOrder> list = consultationInfoRepository.findAll(new Specification<ConsultationInfoOrder>() {
            @Override
            public Predicate toPredicate(Root<ConsultationInfoOrder> root, CriteriaQuery<?> query, CriteriaBuilder builder) {
                List<Predicate> predicateList = new ArrayList<>();
                if (hospitalId != null) {
                    predicateList.add(builder.equal(root.get("hospitalId"), hospitalId));
                } else {
                    String token = LocalRequestUtil.getToken();
                    UserLoginInfo userLoginInfo = GsonUtil.fromJson(redisService.get(token), UserLoginInfo.class);
                    String userId = userLoginInfo.getUserId();
                    predicateList.add(builder.equal(root.get("payAccountId"), userId));
                }
                if (StringUtils.isNotBlank(startDate) && StringUtils.isNotBlank(endDate)) {
                    LocalDate start = DateUtil.stringDate2Date(startDate);
                    LocalDate end = DateUtil.stringDate2Date(endDate);
                    predicateList.add(builder.between(root.get("createTime"), start, end));
                }
                if (StringUtils.isNotBlank(doctorName)) {
                    predicateList.add(builder.like(root.get("doctorName"), doctorName));
                }
                if (StringUtils.isNotBlank(patientName)) {
                    predicateList.add(builder.like(root.get("patientName"), patientName));
                }

                if (StringUtils.isNotBlank(mobile)) {
                    predicateList.add(builder.like(root.get("mobile"), mobile));
                }
                if (StringUtils.isNotBlank(orderNo)) {
                    predicateList.add(builder.like(root.get("orderNo"), orderNo));
                }

                if (orderType != null) {
                    predicateList.add(builder.equal(root.get("orderType"), orderType));
                }
                if (endType != null) {
                    predicateList.add(builder.equal(root.get("endType"), endType));
                }
                if (state != null) {
                    predicateList.add(builder.equal(root.get("state"), state));
                }
                if (refundStatus != null) {
                    predicateList.add(builder.equal(root.get("refundStatus"), refundStatus));
                }
                if (payStatus != null) {
                    predicateList.add(builder.equal(root.get("payStatus"), payStatus));
                }
                Predicate[] predicates = new Predicate[predicateList.size()];
                return query.where(predicateList.toArray(predicates)).getRestriction();
            }
        }, pageable);
        List<ConsultationInfoOrderDTO> consultationInfoOrderDTOS = new ArrayList<>();
        for (ConsultationInfoOrder consultationInfoOrder : list.getContent()) {
            ConsultationInfoOrderDTO consultationInfoOrderDTO = new ConsultationInfoOrderDTO();
            BeanUtils.copyProperties(consultationInfoOrder, consultationInfoOrderDTO);
            String doctorId = consultationInfoOrderDTO.getDoctorId();
            DoctorDTO doctorDTO = hospitalServerFeignClient.info(doctorId);
            consultationInfoOrderDTO.setDoctorAvatar(doctorDTO == null ? "" : doctorDTO.getHeadImg());
            consultationInfoOrderDTO.setOfficer(doctorDTO == null ? "" : doctorDTO.getOfficer());
            MedicalRecord medicalRecord = medicalRecordRepository.findFirstByConsultationId(consultationInfoOrder.getId());
            if (StringUtils.isNotEmpty(consultationInfoOrder.getPatientCardId())) {
                Optional<PatientCardInfo> patientCardInfo = this.patientCardInfoRepository.findById(consultationInfoOrder.getPatientCardId());
                if (patientCardInfo.isPresent()) {
                    consultationInfoOrderDTO.setPatientCardNo(patientCardInfo.get().getCardNo());
                }
            }
            if (medicalRecord != null) {
                MedicalRecordInfoDTO medicalRecordInfoDTO = new MedicalRecordInfoDTO();
                BeanUtils.copyProperties(medicalRecord, medicalRecordInfoDTO);
                consultationInfoOrderDTO.setMedicalRecordInfoDTO(medicalRecordInfoDTO);
            } else {
                consultationInfoOrderDTO.setMedicalRecordInfoDTO(null);
            }
            List<File> files = fileRepository.findAllByBusinessId(consultationInfoOrder.getId());
            List<String> imgs = files.stream().map(File::getPath).collect(Collectors.toList());
            consultationInfoOrderDTO.setImgs(imgs);
            consultationInfoOrderDTOS.add(consultationInfoOrderDTO);
        }
        PageData page = new PageData();
        page.setList(consultationInfoOrderDTOS);
        page.setCurrentPage(current);
        page.setPageSize(size);
        page.setTotalCount(list.getTotalElements());
        return page;
    }

    @Override
    public void complete() {
        Integer[] states = {1, 2};
        List<ConsultationInfoOrder> consultationInfoOrders = consultationInfoRepository.findAllByStateIn(states);
        List<ConsultationInfoOrder> consultationInfoOrderList = new ArrayList<>();
        for (ConsultationInfoOrder consultationInfoOrder : consultationInfoOrders) {
            LocalDateTime endDateTime = consultationInfoOrder.getServiceEndTime();
            if(consultationInfoOrder.getState() == 1) {//一直没有接诊 没有 serviceEndTime
                endDateTime = consultationInfoOrder.getEndDatetime();
            }

            LocalDateTime now = LocalDateTime.now();
            log.error("定时任务，ServiceEndTime is:{},now is{},endDateTime.isBefore(now) is{}", DateUtil.dateTimeToString(endDateTime), DateUtil.dateTimeToString(now), endDateTime.isBefore(now));
            if (endDateTime.isBefore(now)) {
                consultationInfoOrder.setAuth(0);
                consultationInfoOrder.setEndType(1);
                consultationInfoOrderList.add(consultationInfoOrder);
                //向患者发送服务已结束的消息
                Map dataMap = new HashMap();
                dataMap.put("type", 4);
                dataMap.put("data", "本次服务已结束");
                paymentService.sendPayedMsg(consultationInfoOrder.getDoctorTencentAccountId(), consultationInfoOrder.getPatientTencentAccountId(), JSON.toJSONString(dataMap, SerializerFeature.WriteNullStringAsEmpty), 1);
                if(consultationInfoOrder.getOrderType() != 16 && consultationInfoOrder.getState() == 1){//非续方问诊的 一直没有接诊,退款
                    BigDecimal fen = consultationInfoOrder.getPayAmount().multiply(new BigDecimal("100")); //1.00
                    if(this.payFeignClient.refundForUsercenter(consultationInfoOrder.getOrderNo(), fen.intValue(), consultationInfoOrder.getHospitalId())){
                        consultationInfoOrder.setState(4);
                        consultationInfoOrder.setRefundStatus(1);
                        consultationInfoOrder.setRefundTime(LocalDateTime.now());
                    }
                }else{
                    consultationInfoOrder.setState(3);
                }
            }
        }
        consultationInfoRepository.saveAll(consultationInfoOrderList);
    }

    @Override
    public ConsultationInfoDTO info(String accountId, String doctorId, String consultationInfoId, String prescriptionId) {

        ConsultationInfoOrder consultationInfoOrder = new ConsultationInfoOrder();
        ConsultationInfoDTO consultationInfoDTO = new ConsultationInfoDTO();
        if (StringUtils.isNotBlank(accountId)) {
            //TODO 前端会话里拿不到doctorId
            if (accountId.startsWith(this.prefix)) {
                accountId = accountId.substring(this.prefix.length());
            }
            consultationInfoOrder = consultationInfoRepository.findFirstByPayAccountIdOrderByPayTimeDesc(accountId);
            log.info("accountId:{}",accountId);
        }
        if (StringUtils.isNotBlank(consultationInfoId)) {
            consultationInfoOrder = consultationInfoRepository.findById(consultationInfoId).orElse(null);
        }
        if (StringUtils.isNotBlank(doctorId)) {
            if (doctorId.startsWith(this.prefix)) {
                doctorId = doctorId.substring(this.prefix.length());
            }
            log.info("doctorId:{}",doctorId);
            String token = LocalRequestUtil.getToken();
            log.info("token:{}",token);
            UserLoginInfo userLoginInfo = GsonUtil.fromJson(redisService.get(token), UserLoginInfo.class);
            log.info("userLoginInfo:{}",userLoginInfo);
            String userId = userLoginInfo.getUserId();
            log.info("userId:{}",userId);
            consultationInfoOrder = consultationInfoRepository.findFirstByDoctorIdAndPayAccountIdOrderByCreateTimeDesc(doctorId, userId);
        }
        if(StringUtils.isNotBlank(prescriptionId)){
            consultationInfoOrder = consultationInfoRepository.findFirstByPrescriptionId(prescriptionId);
        }
        if (consultationInfoOrder != null) {
            String cardId = consultationInfoOrder.getPatientCardId();
            PatientCardInfo patientCardInfo = patientCardInfoRepository.findById(cardId).orElse(null);
            BeanUtils.copyProperties(consultationInfoOrder, consultationInfoDTO);
            consultationInfoDTO.setPatientCardInfo(patientCardInfo);
            List<File> files = fileRepository.findAllByBusinessIdOrderBySort(consultationInfoDTO.getId());
            List<String> paths = files.stream().map(File::getPath).collect(Collectors.toList());
            LocalDate date = consultationInfoOrder.getDate();
            LocalDateTime startDateTime = consultationInfoOrder.getStartDatetime();
            LocalDateTime endDateTime = consultationInfoOrder.getEndDatetime();
            consultationInfoDTO.setWaitingTreatment(DateUtil.dateTimeToString(startDateTime) + "-" + DateUtil.dateTimeToHourMinutes(endDateTime));
            MedicalRecord medicalRecord = medicalRecordRepository.findFirstByConsultationId(consultationInfoOrder.getId());
            consultationInfoDTO.setMedicalRecord(medicalRecord);
            List<Evaluation> evaluations = evaluationRepository.findAllByConsultationId(consultationInfoOrder.getId());
            consultationInfoDTO.setEvaluations(evaluations);
            consultationInfoDTO.setImgs(paths);
            if (StringUtils.isNotBlank(doctorId)) {
                List<DoctorOnlinePriceSettingDTO> doctorOnlinePriceSettingDTOS = hospitalServerFeignClient.doctorOnlineConfigInfo(doctorId);
                DoctorDTO doctorDTO = hospitalServerFeignClient.info(doctorId);
                consultationInfoDTO.setDoctorOnlinePriceSettingDTOS(doctorOnlinePriceSettingDTOS);
                consultationInfoDTO.setDoctorDTO(doctorDTO);
            }
//            consultationInfoDTO.setDoctorDetailDTO(doctorService.evaluate(doctorId));
        }

        return consultationInfoDTO;
    }

    @Override
    public ConsultationStatisticsDto statistics(String doctorId) {
        LocalDate localDate = LocalDate.now();
        int[] s = {1, 2, 3};
        Integer consultationInfoOrderTodayCount = consultationInfoRepository.countAllByDateAndDoctorIdAndStateIn(localDate, doctorId, s);
        int[] arr = {1, 2};
        Integer registeOrderTodayCount = registerOrderRepository.countByDateAndDoctorIdAndStateIn(localDate, doctorId, arr);
        Integer consultationWait = consultationInfoRepository.countAllByDoctorIdAndState(doctorId, 1);
        Integer consultationing = consultationInfoRepository.countAllByDoctorIdAndState(doctorId, 2);
        return ConsultationStatisticsDto.builder()
                .consultationInfoOrderTodayCount(consultationInfoOrderTodayCount)
                .consultationing(consultationing)
                .consultationWait(consultationWait)
                .registeOrderTodayCount(registeOrderTodayCount).build();
    }

    @Override
    public List<DoctorConsultationCountDto> doctorConsultationCount(List<String> doctorIds) {
        //医生问诊统计
        List allByDoctorIdInGroups = this.consultationInfoRepository.countByDoctorIdInGroup(doctorIds);

        //医生评分统计,评分 = 总分 / 评价次数
        List scoreByDoctorIdInGroup = this.evaluationRepository.scoreByDoctorIdInGroup(doctorIds);

        //医生平均问诊响应时间,接诊时间大于 预约时间的当天10点 开始算响应时间,提前接诊算0分响应速度
        List avgReceiveTimeByDoctorGroup = this.consultationInfoRepository.avgReceiveTimeByDoctorGroup(doctorIds);

        ArrayList<DoctorConsultationCountDto> doctorConsultationCountDtos = new ArrayList<>();
        for (String doctorId : doctorIds) {
            DoctorConsultationCountDto doctorConsultationCountDto = DoctorConsultationCountDto.builder()
                    .doctorId(doctorId)
                    .build();

            Iterator allByDoctorIdInGroupIterator = allByDoctorIdInGroups.iterator();
            while (allByDoctorIdInGroupIterator.hasNext()) {
                Object[] o = (Object[]) allByDoctorIdInGroupIterator.next();
                if (doctorId.equals(o[0].toString())) {
                    doctorConsultationCountDto.setConsultationCount(StringUtil.string2int(o[1].toString()));
                    allByDoctorIdInGroupIterator.remove();
                    break;
                }
            }

            Iterator scoreByDoctorIdInGroupIterator = scoreByDoctorIdInGroup.iterator();
            while (scoreByDoctorIdInGroupIterator.hasNext()) {
                Object[] o = (Object[]) scoreByDoctorIdInGroupIterator.next();
                if (doctorId.equals(o[0].toString())) {
                    int scoreTimes = StringUtil.string2int(o[1].toString());
                    int scoreTotal = StringUtil.string2int(o[2].toString());
                    doctorConsultationCountDto.setScoreTimes(scoreTimes);
                    doctorConsultationCountDto.setScoreTotal(scoreTotal);
                    NumberFormat numberFormat = NumberFormat.getInstance();
                    // 设置精确到小数点后2位
                    numberFormat.setMaximumFractionDigits(1);
                    String result = numberFormat.format((float) scoreTotal / (float) scoreTimes);
                    doctorConsultationCountDto.setScoreAvg(result);
                    result = numberFormat.format((float) scoreTotal / ((float) scoreTimes * 5) * 100);
                    doctorConsultationCountDto.setPraisePer(result);
                    scoreByDoctorIdInGroupIterator.remove();
                    break;
                }
            }

            Iterator avgReceiveTimeByDoctorGroupIterator = avgReceiveTimeByDoctorGroup.iterator();
            while (avgReceiveTimeByDoctorGroupIterator.hasNext()) {
                Object[] o = (Object[]) avgReceiveTimeByDoctorGroupIterator.next();
                if (doctorId.equals(o[0].toString())) {
                    String receiveTimeAvg = o[1].toString();
                    if (StringUtils.isNotEmpty(receiveTimeAvg)) {
                        doctorConsultationCountDto.setReceiveTimeAvg(StringUtil.string2int(receiveTimeAvg.substring(0, receiveTimeAvg.indexOf("."))));
                    }
                    avgReceiveTimeByDoctorGroupIterator.remove();
                    break;
                }
            }

            doctorConsultationCountDtos.add(doctorConsultationCountDto);
        }

        return doctorConsultationCountDtos;
    }

    @Override
    public ConsultationOrderInfoDTO orderInfo(String orderNo) {
        ConsultationInfoOrder consultationInfoOrder = consultationInfoRepository.findFirstByOrderNo(orderNo);
        if (consultationInfoOrder == null) {
            throw new NormalException(ResultEnums.NO_EXIST_ORDERNO_ERROR, String.format("订单【%s】不存在", orderNo));
        }
        ConsultationOrderInfoDTO consultationOrderInfoDTO = new ConsultationOrderInfoDTO();
        BeanUtils.copyProperties(consultationInfoOrder, consultationOrderInfoDTO);
        return consultationOrderInfoDTO;
    }

    @Override
    public void auth(String consultationId, int type) {
        ConsultationInfoOrder consultationInfoOrder = consultationInfoRepository.
                findById(consultationId).orElseThrow(() -> new NormalException(ResultEnums.NOT_EXIST));
        consultationInfoOrder.setAuth(1);
        consultationInfoRepository.save(consultationInfoOrder);
        if (type == 1) {
            Optional<Patient> optional = this.patientRepository.findById(consultationInfoOrder.getPayAccountId());
            if (optional.isPresent()) {
                messageFeignClient.smsPatientgGrant(optional.get().getMobile(), consultationInfoOrder.getDoctorName());
            }
        }
    }

    @Override
    public String again(AddAgainConsultationOrderForm addAgainConsultationOrderForm) {


        if (StringUtils.isBlank(addAgainConsultationOrderForm.getPatientId())) {
            PatientCardInfo patientCardInfo = patientCardInfoRepository.findById(addAgainConsultationOrderForm.getPatientCardId()).orElseThrow(() -> new NormalException(ResultEnums.NOT_EXIST));
            addAgainConsultationOrderForm.setPatientId(patientCardInfo.getAccountId());
        }

        if (checkConsulting(addAgainConsultationOrderForm.getPatientId(), addAgainConsultationOrderForm.getDoctorId())) {
            throw new NormalException(ResultEnums.HAS_UNFINISHED_ORDER_ERROR);
        }
        String token = LocalRequestUtil.getToken();
        UserLoginInfo userLoginInfo = GsonUtil.fromJson(redisService.get(token), UserLoginInfo.class);
        String userId = userLoginInfo.getUserId();
        Integer hospitalId = addAgainConsultationOrderForm.getHospitalId();
        ConsultationInfoOrder consultationInfo = new ConsultationInfoOrder();
        BeanUtils.copyProperties(addAgainConsultationOrderForm, consultationInfo);
        DoctorDTO doctorDTO = hospitalServerFeignClient.info(addAgainConsultationOrderForm.getDoctorId());
        if (doctorDTO == null || StringUtils.isEmpty(doctorDTO.getTencentAccountId())) {
            throw new NormalException(ResultEnums._2210);
        }
        consultationInfo.setDoctorTencentAccountId(doctorDTO.getTencentAccountId());
        consultationInfo.setPatientTencentAccountId(userLoginInfo.getTencentAccountId());
        String id = LocalStringUtil.getUUID();
        PatientCardInfo patientCardInfo = patientCardInfoRepository.findById(consultationInfo.getPatientCardId()).orElse(null);
        if (patientCardInfo != null) {
            BeanUtils.copyProperties(patientCardInfo, consultationInfo);
            consultationInfo.setNameFamily(patientCardInfo.getNation());
        } else {
            throw new NormalException(ResultEnums.PATIENTCARD_ERROR);
        }

        consultationInfo.setPayAccountId(userId);
        consultationInfo.setPayType(1);
        consultationInfo.setBirthday(patientCardInfo.getBirthday());
        consultationInfo.setSex(patientCardInfo.getSex());
        consultationInfo.setStartDatetime(LocalDateTime.now());
        consultationInfo.setEndDatetime(LocalDateTime.now().plusHours(2));
        consultationInfo.setDate(LocalDate.now());
        consultationInfo.setAge(patientCardInfo.getAge());
        String orderNo = OrderUtil.getOrderNo(hospitalId, 16);
        consultationInfo.setOrderNo(orderNo);
        consultationInfo.setPatientName(patientCardInfo.getPatientName());
        consultationInfo.setMedicalHistory(patientCardInfo.getPresentIllnessHistory());
        consultationInfo.setPayAmount(BigDecimal.ZERO);
        consultationInfo.setPayTime(LocalDateTime.now());
        consultationInfo.setId(id);
        consultationInfo.setPayStatus(1);
        consultationInfo.setState(1);
        consultationInfo.setOrderType(16);
        consultationInfo.setPrescriptionId(addAgainConsultationOrderForm.getPrescriptionId());
        consultationInfoRepository.save(consultationInfo);

        Map dataMap = new HashMap();
        //患者给医生发送消息：支付已成功的消息
        dataMap.put("type",1);
        dataMap.put("data","患者已一键续方！请在尽快接诊");
        this.paymentService.sendPayedMsg(consultationInfo.getPatientTencentAccountId(), consultationInfo.getDoctorTencentAccountId(), JSON.toJSONString(dataMap,SerializerFeature.WriteNullStringAsEmpty),2);

        return id;
    }

    @Override
    public String prescriptionBinding(PrescriptionBindingForm prescriptionBindingForm) {
        boolean needBinding = false;
        if(prescriptionBindingForm.getType().equals(PrescriptionType.west)){
            //根据药品类型和数量判断是否需要创建处方
            needBinding = prescriptionBindingForm.getWestDrugList() != null && prescriptionBindingForm.getWestDrugList().size() > 0;
        }else{
            needBinding = prescriptionBindingForm.getChinaDrugList() != null && prescriptionBindingForm.getChinaDrugList().size() > 0;
        }

        if(needBinding){
            ResultVO<String> prescription = this.prescriptionFeignClient.createPrescription(prescriptionBindingForm);
            if (prescription != null && prescription.getCode() == 0) {
                String prescriptionId = prescription.getData();
                ConsultationInfoOrder consultationInfoOrder = consultationInfoRepository.
                        findById(prescriptionBindingForm.getConsultationId()).orElseThrow(() -> new NormalException(ResultEnums.NOT_EXIST));
                consultationInfoOrder.setPrescriptionId(prescriptionId);
                this.consultationInfoRepository.save(consultationInfoOrder);
                return prescriptionId;
            }
        }
        return null;
    }
}
